# !/usr/bin/env python3
# -*- coding: utf-8 -*-


import math
import xml.etree.ElementTree as EleTree
from util.txt_engine import write_topo_or_stream_to_txt


def transforming_flow_feature(flow_xml, topo_xml, flow_txt):
    """
    将xml格式的流特征转换为txt格式
    """
    # 从flow_feature.xml文件中挑选出
    # 每一条流量的
    # flow_id, size, period, latency_requirement, jitter_requirement, route六个参数
    # 上述六个参数分别对应stream_txt中的
    # stream_id, size, period, latency_requirement, jitter_requirement, route
    tree = EleTree.parse(flow_xml)

    flow_set_ele = tree.findall('flow')
    flow_set = []
    for flow_ele in flow_set_ele:
        # 判断流类型
        flow_type = flow_ele.findtext('flow_type')
        # 如果这条流是AVB流
        if flow_type == 'AVB':
            continue

        flow = {}
        # flow_id
        flow_id = flow_ele.findtext("stream_id")
        # size, period, latency_requirement, jitter_requirement,
        size = flow_ele.findtext("size")
        period = flow_ele.findtext("period")
        latency_requirement = flow_ele.findtext("latency_requirement")
        jitter_requirement = flow_ele.findtext("jitter_requirement")
        flow.update({'stream_id': flow_id,
                     'size': size,
                     'period': period,
                     'latency_requirement': latency_requirement,
                     'jitter_requirement':jitter_requirement
                     })

        # route
        # 首先找到所有的node_id和port_id的对
        # 然后根据topo_xml的信息，将这些对转化成相应的link_id
        route_eles = flow_ele.findall("route")
        link_id_set = []
        for route_ele in route_eles:
            link_id = int(route_ele.text)
            link_id_set.append(link_id)
        flow.update({'route': link_id_set})
        flow_set.append(flow)

    # 将这些参数写入stream_txt文件
    write_topo_or_stream_to_txt(flow_txt, flow_set)
    return


def transforming_node_and_port_into_link(route_set, topo_xml):
    # 读取topo_xml中的每一条链路
    tree = EleTree.parse(topo_xml)
    link_id_ele_set = tree.iter('link_id')
    link_id_set = [link_id_ele.text for link_id_ele in link_id_ele_set]
    src_node_id_ele_set = tree.iter('src_node')
    src_node_id_set = [src_node_id_ele.text for src_node_id_ele in src_node_id_ele_set]
    src_port_id_ele_set = tree.iter('src_port')
    src_port_id_set = [src_port_id_ele.text for src_port_id_ele in src_port_id_ele_set]

    link_set = [[link_id, src_node, src_port] for link_id, src_node, src_port in
                zip(link_id_set, src_node_id_set, src_port_id_set)]
    return_link_id_set = []
    for route in route_set:
        node_id = route[0]
        port_id = route[1]
        for link in link_set:
            if node_id == link[1] and port_id == link[2]:
                link_id = link[0]
                return_link_id_set.append(link_id)
                break

    return return_link_id_set


def get_route_path(flow_xml, topo_set):
    """
    从flow_xml中获取流量的路由路径，链路和节点端口两种表示
    """
    route_set = []
    root = EleTree.parse(flow_xml)
    flow_ele_set = root.findall('flow')
    for flow_ele in flow_ele_set:
        # 获得当前流量的flow_id
        flow_id = flow_ele.findtext('stream_id')
        flow_id = int(flow_id)
        flow_type = flow_ele.findtext('flow_type')
        # 获得当前流量的路由路径
        route_path = []
        route_link = []
        route_eles = flow_ele.findall('route')
        for route_ele in route_eles:
            link_id = int(route_ele.text)
            route_link.append(link_id)
            for topo_entry in topo_set:
                if link_id == topo_entry['link_id']:
                    route_path.append([topo_entry['src_node_id'], topo_entry['src_port_id']])
                    continue
        link_id = int(route_eles[-1].text)
        for topo_entry in topo_set:
            if link_id == topo_entry['link_id']:
                route_path.append([topo_entry['dst_node_id'], topo_entry['dst_port_id']])
                continue
        route_set.append(
            {'flow_id': flow_id,
             'flow_type': flow_type,
             'route_link': route_link,
             'route_node_port': route_path,
             'src_node_id': route_path[0][0],
             'src_port_id': route_path[0][1],
             'dst_node_id': route_path[-1][0],
             'dst_port_id': route_path[-1][1],
             'first_hop_link_id': route_link[0]
             }
        )

    return route_set


def compute_sched_period(flow_xml):
    """
    计算调度周期
    """
    period_set = []

    root = EleTree.parse(flow_xml)
    flow_ele_set = root.findall('flow')
    for flow_ele in flow_ele_set:
        # 获取当前的流量类型
        flow_type = flow_ele.findtext('flow_type')

        # 如果当前流量是ST流
        if flow_type == 'ST':
            # 获得当前流量的周期
            period_ele = flow_ele.iter('period')
            period_ele = list(period_ele)
            period = period_ele[0].text
            period = int(period)
        elif flow_type == 'AVB':
            period = 0

        if period != 0:
            period_set.append(period)

    sched_period = 1
    for period in period_set:
        sched_period = int(period) * int(sched_period) / \
                       math.gcd(int(period), int(sched_period))
    sched_period = int(sched_period)

    return sched_period

